#!/usr/bin/perl

use warnings;
use strict;

#################################################################################
## This file checks to see if a Verilog file will be synthesized as intended.
##
## To run:
## perl synth_check.pl <Verilog file>.v
################################################################################

my $vfile = $ARGV[0];

# Open files
open(VIN, "$vfile") || die("Could not open file!");

my $i;
my $j;
my $subarray_len;
my $line;
my @tokens;
my $tokens;
my $num_lines = 0;
my $num_always = 0;
my $num_vars = 0;
my @always_vars;

# Boolean variable for being in an always block
my $in_always = 0;
my $in_if = 0;
my $block_comment = 0;

# Checks:
# 1. Non-concurrent assignment statements in always blocks
# 2. Multiple assignments to one variable in multiple always blocks
while ($line = <VIN>) {
    chomp($line);
	$num_lines += 1;
	if (length($line) > 0 && substr($line, 0, 2) ne "//") {
		# Split line string into tokens delimited by white space
		@tokens = split(' ', $line);
		$tokens = @tokens;
		
		# Prune all comments out of tokens array
		for ($i = 0; $i < $tokens; $i++) {
			if ($tokens[$i] =~ m/\/\//) {
				# If a comment is found, remove this array element and the rest
				@tokens = @tokens[0,$i-1];
				$tokens = @tokens;
				last;
			}
		}
		
		# Check for block comment (/* */)
		if ($line =~ m/\/\*/) {
			$block_comment = 1;
			# iterate until end of block comment
			while ($line = <VIN> && $block_comment eq 1) {
				if ($line =~ m/\*\//) {
					$block_comment = 0;
				}
			}
		}
		else {
		
			if ($tokens gt 0) {
				if ($tokens[0] eq "always") {
					if ($in_always eq 1) {
						$num_always += 1;
					}
					$in_always = 1;
					$num_vars = 0;
				}
				elsif ($in_always eq 1 && $tokens gt 1) {
					if ($tokens[1] eq "=") {					
						print "There is a non-concurrent assignment (=) statement in an always block on line $num_lines.\n";
						push(@{$always_vars[$num_always]}, $tokens[0]);
						$num_vars += 1;
					}
					elsif ($tokens[1] eq "<=") {
						push(@{$always_vars[$num_always]}, $tokens[0]);
						$num_vars += 1;
					}
				}
			}
		}
	}
	
}

# Check to see if any variables assigned in one always block can be found any others
for ($i = 0; $i < $num_always; $i++) {
	# Uniquify the array
	my %temp_hash = map { $_, 0 } @{$always_vars[$i]};
	my @uniq_array = keys %temp_hash;	
	$subarray_len = @uniq_array;
	for ($j = 0; $j < $subarray_len; $j++) {
		if (/^$always_vars[$i][$j]$/ ~~ @{$always_vars[$i+1]}) {
			print "Register '$always_vars[$i][$j]' being assigned in multiple always blocks!\n";
		}
	}
}

